package com.example.flutter_spectrum


import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.net.Uri
import android.os.Handler
import android.util.Log
import com.google.android.exoplayer2.DefaultRenderersFactory
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.Player.Listener
import com.google.android.exoplayer2.Renderer
import com.google.android.exoplayer2.audio.AudioCapabilities
import com.google.android.exoplayer2.audio.AudioRendererEventListener
import com.google.android.exoplayer2.audio.AudioSink
import com.google.android.exoplayer2.audio.DefaultAudioSink
import com.google.android.exoplayer2.audio.MediaCodecAudioRenderer
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.EventChannel.EventSink
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

/** FlutterSpectrumPlugin */
class FlutterSpectrumPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
    private val TAG: String = "AudioSpectrumPlugin"
    private var isPlay: Boolean = false;
    private var player: ExoPlayer? = null
    private lateinit var mContext: Context
    private var mActivity: Activity? = null
    private lateinit var channel: MethodChannel

    private var eventSink: EventSink? = null
    private lateinit var eventChannel: EventChannel

    private var playCompleteSink: EventSink? = null
    private lateinit var playCompleteChannel: EventChannel


    override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        mContext = flutterPluginBinding.applicationContext
        channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_spectrum")
        channel.setMethodCallHandler(this)

        eventChannel = EventChannel(
            flutterPluginBinding.binaryMessenger,
            "flutter_spectrum.events"
        )

        playCompleteChannel = EventChannel(
            flutterPluginBinding.binaryMessenger,
            "flutter_spectrum.play.complete"
        )

        eventChannel.setStreamHandler(pcmStreamHandler)
        playCompleteChannel.setStreamHandler(playCompleteStreamHandler)
    }

    override fun onMethodCall(call: MethodCall, result: Result) {
        if (call.method == "startPlay") {
            val filePath: String = call.argument<String>("filePath")!!
            startPlay(filePath)
        } else if (call.method == "stopPlay") {
            stopPlayer()
        } else {
            result.notImplemented()
        }
    }

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        mActivity = binding.activity
        Log.d(TAG, "onAttachedToActivity: ")
    }

    override fun onDetachedFromActivityForConfigChanges() {
        onDetachedFromActivity()
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        onAttachedToActivity(binding)
    }

    override fun onDetachedFromActivity() {
        stopPlayer()
        mActivity = null
    }

    override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
        channel.setMethodCallHandler(null)
        eventChannel.setStreamHandler(null)
    }

    private val pcmStreamHandler = object : EventChannel.StreamHandler {
        override fun onListen(p0: Any?, p1: EventSink?) {
            if (p1 != null) {
                eventSink = p1
            }
        }

        override fun onCancel(p0: Any?) {

        }
    }

    private val playCompleteStreamHandler = object : EventChannel.StreamHandler {
        override fun onListen(p0: Any?, p1: EventSink?) {
            if (p1 != null) {
                playCompleteSink = p1
            }
        }

        override fun onCancel(p0: Any?) {

        }
    }


    private fun startPlay(url: String) {
        stopPlayer()
        isPlay = true
        val uri: Uri = Uri.parse(url)

        val fftAudioProcessor = PcmAudioProcessor(listenerImplementation)

        val renderersFactory = object : DefaultRenderersFactory(mContext) {

            override fun buildAudioRenderers(
                context: Context,
                extensionRendererMode: Int,
                mediaCodecSelector: MediaCodecSelector,
                enableDecoderFallback: Boolean,
                audioSink: AudioSink,
                eventHandler: Handler,
                eventListener: AudioRendererEventListener,
                out: ArrayList<Renderer>
            ) {
                out.add(
                    MediaCodecAudioRenderer(
                        context,
                        mediaCodecSelector,
                        enableDecoderFallback,
                        eventHandler,
                        eventListener,
                        DefaultAudioSink(
                            AudioCapabilities.getCapabilities(context),
                            arrayOf(fftAudioProcessor)
                        )
                    )
                )

                super.buildAudioRenderers(
                    context,
                    extensionRendererMode,
                    mediaCodecSelector,
                    enableDecoderFallback,
                    audioSink,
                    eventHandler,
                    eventListener,
                    out
                )
            }
        }

        player = ExoPlayer.Builder(mContext, renderersFactory).build()

        // 添加播放状态监听器
        player?.addListener(object : Listener {
            override fun onPlaybackStateChanged(playbackState: Int) {
                if (playbackState == Player.STATE_ENDED) {
                    isPlay = false
                    mActivity?.runOnUiThread {
                        playCompleteSink?.success(null);
                    }
                }
            }
        })


        val mediaSource = ProgressiveMediaSource.Factory(
            DefaultDataSourceFactory(mContext, "ExoVisualizer")
        ).createMediaSource(MediaItem.Builder().setUri(uri).build())
        player?.playWhenReady = true
        player?.setMediaSource(mediaSource)
        player?.prepare()

    }

    private fun stopPlayer() {
        isPlay = false
        try {
            if (player != null) {
                player?.stop()
                player?.release()
                player = null
            }
        } catch (e: Exception) {
            Log.d(TAG, "stopPlayer: $e")
        }
    }

    private val listenerImplementation = object : PcmAudioProcessor.PcmListener {
        override fun onPcmReady(sampleRateHz: Int, channelCount: Int, pcm: DoubleArray) {
            if (isPlay) {
                mActivity?.runOnUiThread {
                    eventSink?.success(pcm);
                }
            }

        }
    }
}
